package com.jms.framework.config;

import com.alibaba.fastjson.JSONObject;
import com.jms.tools.util.MapUtils;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Properties;

/**
 * 抽象配置类，实现了JmsConfig接口，提供基础的配置加载和管理功能。
 * 支持多种格式的配置文件（properties、xml、json等）。
 */
public abstract class JmsAbstractConfig implements JmsConfig {

    public static final String PROPERTIES_TYPE = "properties";
    public static final String XML_TYPE = "xml";
    public static final String YML_TYPE = "yml";
    public static final String YAML_TYPE = "yaml";
    public static final String JSON_TYPE = "json";

    protected Properties properties;
    protected String configName;
    protected String configType;
    protected String configLocation;
    protected Class<?> bootClass;
    protected HashMap<String, String> attributeMap = new HashMap<>();

    /**
     * 获取当前加载的Properties对象。
     *
     * @return 当前加载的Properties对象
     */
    @Override
    public Properties getProperties() {
        return properties;
    }

    /**
     * 获取启动类的Class对象。
     *
     * @return 启动类的Class对象
     */
    @Override
    public Class<?> getBootClass() {
        return bootClass;
    }

    /**
     * 初始化配置的方法，子类可重写以实现自定义初始化逻辑。
     */
    @Override
    public void initConfig() {
    }

    /**
     * 根据配置路径或默认资源路径解析配置文件。
     * 如果configLocation不为空，则使用该路径加载配置；
     * 否则从类路径下加载名为"configName.configType"的资源。
     */
    public void resolveConfig() {
        if (configLocation != null) {
            resolveConfig(configLocation);
        } else {
            InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(String.format("%s.%s", configName, configType));
            resolveConfig(inputStream);
        }
    }

    /**
     * 通过输入流解析配置文件并加载到Properties对象中。
     * 支持的配置类型包括：properties、xml、json。
     *
     * @param inputStream 配置文件的输入流
     * @throws RuntimeException 当配置类型不支持或IO异常时抛出运行时异常
     */
    public void resolveConfig(InputStream inputStream) {
        try {
            properties = new Properties();
            if (PROPERTIES_TYPE.equalsIgnoreCase(configType)) {
                properties.load(inputStream);
            } else if (XML_TYPE.equalsIgnoreCase(configType)) {
                properties.loadFromXML(inputStream);
            } else if (JSON_TYPE.equalsIgnoreCase(configType)) {
                BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
                StringBuilder content = new StringBuilder();
                String line;
                while ((line = reader.readLine()) != null) {
                    content.append(line);
                }
                properties.putAll(MapUtils.ObjectMapToStringMap(MapUtils.getSingleLayerMap(JSONObject.parseObject(content.toString()), null)));
            } else {
                throw new RuntimeException("The config type must be: properties xml json");
            }
            if (inputStream != null) {
                inputStream.close();
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 通过指定的文件路径解析配置文件。
     *
     * @param configPath 配置文件的完整路径
     * @throws RuntimeException 当文件读取失败或解析出错时抛出运行时异常
     */
    public void resolveConfig(String configPath) {
        try {
            InputStream inputStream = Files.newInputStream(Paths.get(configPath));
            resolveConfig(inputStream);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 销毁配置的方法，子类可重写以实现自定义销毁逻辑。
     */
    @Override
    public void destroy() {

    }

    /**
     * 获取指定属性名的属性值。
     *
     * @param attributeName 属性名称
     * @return 对应的属性值，若不存在则返回null
     */
    @Override
    public String getAttribute(String attributeName) {
        return attributeMap.get(attributeName);
    }

    /**
     * 设置属性名和属性值。
     *
     * @param attributeName  属性名称
     * @param attributeValue 属性值
     */
    @Override
    public void setAttribute(String attributeName, String attributeValue) {
        attributeMap.put(attributeName, attributeValue);
    }

    /**
     * 移除指定属性名的属性。
     *
     * @param attributeName 要移除的属性名称
     */
    @Override
    public void removeAttributeValue(String attributeName) {
        attributeMap.remove(attributeName);
    }
}
